package com.example.demo.controller

import com.example.demo.dto.ArtworkEditDto
import com.example.demo.dto.ArtworkDto
import com.example.demo.dto.ArtworkUploadDto
import com.example.demo.dto.ArtworkShowDto
import com.example.demo.entity.Artwork
import com.example.demo.entity.ArtworkCelebrityTitle
import com.example.demo.entity.Celebrity
import com.example.demo.entity.IP
import com.example.demo.repo.*
import jakarta.transaction.Transactional
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.*
import java.util.*

//抽象语法树AST
@RestController
class ArtworkController {

    @Autowired
    lateinit var artworkRepo: ArtworkRepo

    @Autowired
    lateinit var artworkCelebrityTitleRepo: ArtworkCelebrityTitleRepo

    @Autowired
    lateinit var celebrityRepo: CelebrityRepo

    @Autowired
    lateinit var kindRepo: KindRepo

    @Autowired
    lateinit var ipRepo: IpRepo

    @Autowired//依赖注入模式
    lateinit var titleRepo: TitleRepo

    @DeleteMapping("/artwork/{id}")
    @Transactional//事务
    fun deleteArtwork(@PathVariable id: Long) {
//        val actIdsToDelete = artworkCelebrityTitleRepo.findByAidAid(id)
//        artworkCelebrityTitleRepo.deleteAll(actIdsToDelete)
        artworkCelebrityTitleRepo.deleteByAidAid(id)
        artworkRepo.deleteById(id)
    }

//    select * from artwork,kind where name like '%{name}%' and artwork.kid=kind.kid and kind='{category}'

//    select * from artwork,celebrity,artwork_celebrity_title where artwork.aid=artwork_celebrity_title.aid
//    and celebrity.cid=artwork_celebrity_title.cid and celebrity.name like '%{name}%'

//    select * from artwork,celebrity,artwork_celebrity_title where artwork.aid=artwork_celebrity_title.aid
//    and celebrity.cid=artwork_celebrity_title.cid and celebrity.name like '%{name}%' or artwork.name like '%{name}%'

    @GetMapping("/artwork")
    fun test(@RequestParam name: String, category: String): List<ArtworkDto> {
        val result = when (category) {
//            "all" -> artworkRepo.findByNameContainsOrActsCidNameContains(name, name)
            "all" -> artworkCelebrityTitleRepo.findByAidNameContainsOrCidNameContains(name, name).map { it.aid }
//            "staff" -> artworkRepo.findByActsCidNameContains(name)
            "staff" -> artworkCelebrityTitleRepo.findByCidNameContains(name).map { it.aid }
            "ip" -> artworkRepo.findByIpName(name)
            else -> artworkRepo.findByNameContainsAndKidName(name, category)
        }.distinctBy {
            it.aid
        }

        return result.map {
            ArtworkDto(
                it.aid!!,
                it.name,
                it.avatar,
                it.intro,
                it.ip.name,
                it.kid.name,
                it.resourceAddress,
                it.time.time/1000
            )
        }
    }


    @GetMapping("/artwork/{aid}")
    fun getArtworkById(@PathVariable aid: Long): ArtworkShowDto {
        val artwork = artworkRepo.findById(aid).get()
        //findById就是根据主键来找，是一个送的方法，其返回值是一个optional对象，这个对象的get方法是返回一个对象，如果不存在就会报错
        return ArtworkShowDto(
            id = artwork.aid!!,
            atitle = artwork.name,
            avatar = artwork.avatar,
            intro = artwork.intro,
            ip = artwork.ip.name,
            kind = artwork.kid.name,
            resourceAddress = artwork.resourceAddress,
            time = artwork.time.time/1000,
            celebritys = artworkCelebrityTitleRepo.findByAidAid(aid)
                .map { ArtworkShowDto.Celebrity(it.actid!!, it.cid.name, it.tid.tid, it.cid.avatar) }
        )
    }


//    @GetMapping("/artwork")
//    fun getArtworkById(@RequestParam id: Long): ArtworkDto {
//        val artwork=artworkRepo.findById(id).get()
//        //findById就是根据主键来找，是一个送的方法，其返回值是一个optional对象，这个对象的get方法是返回一个对象，如果不存在就会报错
//        return  ArtworkDto(
//                artwork.aid!!,
//                artwork.name,
//                artwork.avatar,
//                artwork.intro,
//                artwork.ip.name,
//                artwork.kid.name
//            )
////        return listOf(artwork).map {
////            ArtworkDto(
////                it.aid!!,
////                it.name,
////                it.avatar,
////                it.intro,
////                it.ip.name,
////                it.kid.name
////            )
////        }
//    }

    @GetMapping("/artwork/edit/{aid}")
    fun test(@PathVariable aid: Long): ArtworkEditDto {
        // get与java的Optional有关，自己实现的找出来你的东西是没有Optional的
        val artwork = artworkRepo.findById(aid).get()

//        println(artwork.acts)
        return ArtworkEditDto(
            artwork.time.time/1000,
            artwork.resourceAddress,
            artwork.avatar,
            artwork.ip.name,
            artwork.aid!!,
            artwork.intro,
            artwork.kid.kid,
            artwork.name,
            artworkCelebrityTitleRepo.findByAidAid(aid).map {
                ArtworkEditDto.Celebrity(it.actid!!, it.cid.name, it.tid.tid, it.cid.avatar)
            }
        )
    }

    @PutMapping("/artwork")
    fun editArtwork(@RequestBody dto: ArtworkEditDto) {
        val a0 = artworkRepo.findById(dto.aid).get()
        a0.name = dto.title
        a0.kid = kindRepo.findById(dto.kind).get()
        a0.intro = dto.intro


        val ipList = ipRepo.findByName(dto.ip)
        val ip =
            if (ipList.isEmpty())
                ipRepo.save(IP(name = dto.ip))
            else
                ipList.first()
        a0.ip = ip
        a0.avatar = dto.avatar
        a0.time = Date(dto.time * 1000)
        a0.resourceAddress = dto.resourceAddress


        val a1 = artworkRepo.save(a0)
        val oldActids = artworkCelebrityTitleRepo.findByAidAid(dto.aid).map { it.actid }.toSet()
        val newActids = dto.celebritys.map { it.actid }.toSet()
        val deleteActids = oldActids - newActids
        println(oldActids)
        println(newActids)
        println(deleteActids)
        artworkCelebrityTitleRepo.deleteAllById(deleteActids)
        println(dto.aid)

        val acts = dto.celebritys.map {
            val names = celebrityRepo.findByName(it.name)
            val name = if (names.isEmpty())
                celebrityRepo.save(Celebrity(it.name, avatar = it.avatar))
            else
                names.first().apply { avatar = it.avatar }
            val title = titleRepo.findById(it.title).get()
            ArtworkCelebrityTitle(a1, title, name, actid = it.actid)
        }

        artworkCelebrityTitleRepo.saveAll(acts)
    }

    @PostMapping("/artwork")
    fun addArtwork(@RequestBody dto: ArtworkUploadDto) {

        val ipList = ipRepo.findByName(dto.ip)//括号里面的就是前端传上来的东西，就是那个输入的系列名字
        val ip = if (ipList.isEmpty())//如果找不到这样一个在数据库中的系列，则ipList.isEmpty会返回True，则需要往IP中添加该系列的名字
            ipRepo.save(IP(name = dto.ip))//如果不存在就往IP数据库中加入一个name为前端输出进来的系列名字的数据
        else
            ipList.first()//如果存在就取出返回值中的第一个元素，返回值也是一个ip的dataclass

        val a1 = artworkRepo.save(
            Artwork(
                name = dto.title,
                time = Date(dto.date * 1000),
                ip = ip,
                kid = kindRepo.findById(dto.kind).get(),
                intro = dto.intro,
                avatar = dto.avatar,
                resourceAddress = dto.resourceAddress,
            )
        )
//      println(a1.name)不要println()外键
        val acts = dto.celebritys.map {
            val celebritiedataclasses = celebrityRepo.findByName(it.name)//先去数据库里面找是否已经存在该人，一个名字只能被一个人拥有
            val celebritydataclass = if (celebritiedataclasses.isEmpty())
            /*返回给name的是
            data class Celebrity(
                val name: String,
                val avatar: String,
                val cid: Long? = null
            )
             */
                celebrityRepo.save(Celebrity(it.name, avatar = it.avatar))//如果不存在则往里面加，返回值也是一个dataclass
            else
                celebritiedataclasses.first()//否则取list中的第一个元素
            val titledataclass = titleRepo.findById(it.title).get()//如果返回值为空则.get()会主动报错.get就是用来检查的
            return@map ArtworkCelebrityTitle(a1, titledataclass, celebritydataclass)//最后一行就是map的返回值
        }
        artworkCelebrityTitleRepo.saveAll(acts)
    }
}
